/*
 * File:   Reader.cpp
 * Author: Elevator
 *
 * Created on July 24, 2013, 8:40 PM
 */

#include <fstream>
#include "Reader.h"
#include "Exceptions.h"

namespace data
{

Reader::Reader( )
{
}

std::string GetFileContents( std::string filename )
{
	std::string text;
	std::ifstream file(filename.c_str());
	if(!file.is_open())
		throw ResourceOpenException( filename );

	while( !file.eof() )
	{
        std::string line;
		file >> line;
		text.append(line);

	}

	file.close();
	return text;
}

Json::Value Reader::ParseFile( std::string filename )
{
	std::string document = GetFileContents( filename );
	Json::Reader reader;
	Json::Value root;

	bool parsingSuccessful = reader.parse( document, root );
	if( !parsingSuccessful )
		throw ParserException( filename, reader.getFormattedErrorMessages( ) );

	return root;
}

const Scene* Reader::ReadScene( const Json::Value& value )
{
	Vector<const Creature*>* creatures = new Vector<const Creature*>( );
	Json::Value jsonCreatures = value["creatures"];
	for( uint i = 0; i < jsonCreatures.size( ); ++i )
		creatures->Add( ReadCreature( jsonCreatures[i] ) );

	Vector<Player>* players = new Vector<Player > ( );
	Json::Value jsonPlayers = value["players"];
	for( uint i = 0; i < jsonPlayers.size( ); ++i )
		players->Add( ReadPlayer( jsonPlayers[i] ) );

	return new Scene(
			   value["name"].asString( ),
			   value["description"].asString( ),
			   players,
			   creatures,
			   ReadMap( ParseFile( value["map"].asString( ) ) ),
			   ReadCamera( value["camera"] ) );
}

const Camera* Reader::ReadCamera( const Json::Value& value )
{
	Transform position = ReadTransform( value["position"] );
	Transform velocity = ReadTransform( value["velocity"] );
	float scale = value["scale"].asFloat( );

	return new Camera( position, velocity, scale );
}

const Map* Reader::ReadMap( const Json::Value& value )
{
	Vector<const Obstacle*>* obstacles = new Vector<const Obstacle*>( );
	Json::Value jsonObstacles = value["obstacles"];
	for( uint i = 0; i < jsonObstacles.size( ); ++i )
		obstacles->Add( ReadObstacle( jsonObstacles[i] ) );

	return new Map(
			   value["name"].asString( ),
			   value["description"].asString( ),
			   obstacles );
}

const Obstacle* Reader::ReadObstacle( const Json::Value& value )
{
	Vector<const Shape*>* shapes = new Vector<const Shape*>( );
	Json::Value jsonShapes = value["shapes"];
	for( uint i = 0; i < jsonShapes.size( ); ++i )
		shapes->Add( ReadShape( jsonShapes[i] ) );

	return new Obstacle(
			   value["id"].asString( ),
			   shapes );
}

const Shape* Reader::ReadShape( const Json::Value& value )
{
	Vector<Circle>* vertices = new Vector<Circle > ( );
	for( uint i = 0; i < value.size( ); ++i )
		vertices->Add( ReadCircle( value[i] ) );

	return new Shape( vertices );
}

Player Reader::ReadPlayer( const Json::Value& value )
{
	return Player(
			   ReadPlayerType( value["type"] ),
			   value["name"].asString( ),
			   value["creature"].asString( ) );
}

PlayerType Reader::ReadPlayerType( const Json::Value & value )
{
	return StringToPlayerType( value.asString( ) );
}

const Creature* Reader::ReadCreature( const Json::Value & value )
{
	return new Creature(
			   value["id"].asString( ),
			   ReadTransform( value["position"] ),
			   ReadCreatureDef( ParseFile( value["definition"].asString( ) ) ) );
}

const CreatureDef* Reader::ReadCreatureDef( const Json::Value & value )
{
	Vector<const Detail*>* details = new Vector<const Detail*>( );
	Json::Value jsonDetails = value["details"];
	for( uint i = 0; i < jsonDetails.size( ); ++i )
		details->Add( ReadDetail( jsonDetails[i] ) );

	Vector<const Rotor*>* rotors = new Vector<const Rotor*>( );
	Json::Value jsonRotors = value["rotors"];
	for( uint i = 0; i < jsonRotors.size( ); ++i )
		rotors->Add( ReadRotor( jsonRotors[i] ) );

	Vector<Link>* links = new Vector<Link > ( );
	Json::Value jsonLinks = value["links"];
	for( uint i = 0; i < jsonLinks.size( ); ++i )
		links->Add( ReadLink( jsonLinks[i] ) );

	return new CreatureDef(
			   value["name"].asString( ),
			   value["description"].asString( ),
			   value["head"].asString( ),
			   details, rotors, links );
}

const Detail* Reader::ReadDetail( const Json::Value & value )
{
	Vector<Rule>* rules = new Vector<Rule > ( );
	Json::Value jsonRules = value["rules"];
	for( uint i = 0; i < jsonRules.size( ); ++i )
		rules->Add( ReadRule( jsonRules[i] ) );

	return new Detail(
			   value["id"].asString( ),
			   ReadTransform( value["position"] ),
			   ReadDetailDef( ParseFile( value["definition"].asString( ) ) ),
			   rules );
}

const DetailDef* Reader::ReadDetailDef( const Json::Value & value )
{
	Vector<Circle>* vertices = new Vector<Circle > ( );
	Json::Value jsonVertices = value["vertices"];
	for( uint i = 0; i < jsonVertices.size( ); ++i )
		vertices->Add( ReadCircle( jsonVertices[i] ) );

	return new DetailDef(
			   value["name"].asString( ),
			   value["description"].asString( ),
			   value["mass"].asFloat( ),
			   value["inertia"].asFloat( ),
			   value["friction"].asFloat( ),
			   value["restitution"].asFloat( ),
			   vertices,
			   ReadModel( ParseFile( value["model"].asString( ) ) ) );
}

const Model* Reader::ReadModel( const Json::Value & value )
{
	return new Model( );
}

const Rotor* Reader::ReadRotor( const Json::Value & value )
{
	Vector<Rule>* rules = new Vector<Rule > ( );
	Json::Value jsonRules = value["rules"];
	for( uint i = 0; i < jsonRules.size( ); ++i )
		rules->Add( ReadRule( jsonRules[i] ) );

	return new Rotor(
			   value["id"].asString( ),
			   value["detailA"].asString( ),
			   value["detailB"].asString( ),
			   ReadVec2( value["position"] ),
			   ReadRotorDef( ParseFile( value["definition"].asString( ) ) ),
			   rules );
}

const RotorDef* Reader::ReadRotorDef( const Json::Value & value )
{
	return new RotorDef(
			   value["name"].asString( ),
			   value["description"].asString( ),
			   value["torque"].asFloat( ) );
}

Link Reader::ReadLink( const Json::Value & value )
{
	return Link( value["partA"].asString( ), value["partB"].asString( ) );

}

Rule Reader::ReadRule( const Json::Value & value )
{
	return Rule(
			   ReadCommand( value["command"] ),
			   ReadAction( value["action"] ) );
}

Command Reader::ReadCommand( const Json::Value & value )
{
	return Command(
			   value["key"].asString( )[0],
			   ParseCommandType( value["type"].asString( ) ) );
}

CommandType Reader::ParseCommandType( const Json::Value & value )
{
	return StringToCommandType( value.asString( ) );
}

Action Reader::ReadAction( const Json::Value & value )
{
	return StringToAction( value.asString( ) );
}

Circle Reader::ReadCircle( const Json::Value & value )
{
	return Circle( ReadVec2( value["position"] ), value["radius"].asFloat( ) );
}

Transform Reader::ReadTransform( const Json::Value & value )
{
	return Transform( ReadVec2( value["vector"] ), value["rotation"].asFloat( ) );
}

Vec2 Reader::ReadVec2( const Json::Value & value )
{
	return Vec2( value["x"].asFloat( ), value["y"].asFloat( ) );
}
}
